Added `-[NSArray validateAsPropertyList]` and `-[NSDictionary validateAsPropertyList...
[adiumx.git] / Plugins / Purple Service / adiumPurpleBlist.m
bloba87c16d8392390243124e34e6da61c0cf3fe028b
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6  * General Public License as published by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
11  * Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License along with this program; if not,
14  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15  */
17 #import "adiumPurpleBlist.h"
18 #import <AIUtilities/AIObjectAdditions.h>
19 #import <Adium/AIListContact.h>
21 static NSMutableDictionary      *groupDict = nil;
22 static NSMutableDictionary      *aliasDict = nil;
24 static void adiumPurpleBlistNewList(PurpleBuddyList *list)
29 static void adiumPurpleBlistNewNode(PurpleBlistNode *node)
31         
34 static void adiumPurpleBlistShow(PurpleBuddyList *list)
36         
39 static void adiumPurpleBlistUpdate(PurpleBuddyList *list, PurpleBlistNode *node)
41         if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
42                 PurpleBuddy *buddy = (PurpleBuddy*)node;
44                 //Take no action if the relevant account isn't online.
45                 if (!purple_buddy_get_account(buddy) || !purple_account_is_connected(purple_buddy_get_account(buddy)))
46                         return;
47                    
48                 AIListContact   *theContact = contactLookupFromBuddy(buddy);
50                 PurpleGroup             *g = purple_buddy_get_group(buddy);
51                 NSString                *groupName = ((g && purple_group_get_name(g)) ? [NSString stringWithUTF8String:purple_group_get_name(g)] : nil);
52                 NSString                *oldGroupName;
53                 NSValue                 *buddyValue = [NSValue valueWithPointer:buddy];
55                 //Group changes, including the initial notification of the group
56                 //We also use this opportunity to check the contact's name against its formattedUID
57                 if (!groupDict) groupDict = [[NSMutableDictionary alloc] init];
59                 /* If there is no old group name, or there is and there is no current group name, or the two don't match,
60                  * update our group information. */
61                 if (!(oldGroupName = [groupDict objectForKey:buddyValue]) ||
62                     !(groupName) ||
63                     !([oldGroupName isEqualToString:groupName])) {
65                         /* We pass in purple_buddy_get_name(buddy) directly (without filtering or normalizing it) as it may indicate a 
66                          * formatted version of the UID.  We have a signal for when a rename occurs, but passing here lets us get
67                          * formatted names which are originally formatted in a way which differs from the results of normalization.
68                          * For example, TekJew will normalize to tekjew in AIM; we want to use tekjew internally but display TekJew.
69                          */
70                         NSString        *contactName;
71                         contactName = [NSString stringWithUTF8String:purple_buddy_get_name(buddy)];
73                         //Store the new string in our aliasDict
74                         if (groupName) {
75                                 [groupDict setObject:groupName forKey:buddyValue];
76                         } else {
77                                 [groupDict removeObjectForKey:buddyValue];
78                         }
80                         [accountLookup(purple_buddy_get_account(buddy)) updateContact:theContact
81                                                                                          toGroupName:groupName
82                                                                                          contactName:contactName];
83                 }
84                 
85                 /* We have no way of differentiating when the buddy's alias changes versus when we get an update
86                  * for a different status event.  We don't want to send to the main thread a used alias every time
87                  * we get any update, but we do want to pass on a changed alias.  We therefore use the static
88                  * aliasDict NSMutableDictionary to track what alias was last used for each buddy.  The first invocation,
89                  * and subsequent invocations for the same alias, are passed back to the main thread for processing. */
90                 const char      *alias = purple_buddy_get_alias_only(buddy);
91                 if (alias) {
92                         NSString        *aliasString = [NSString stringWithUTF8String:alias];
93                         NSString        *oldAliasString;
94                         
95                         if (!aliasDict) aliasDict = [[NSMutableDictionary alloc] init];
97                         if (![aliasString isEqualToString:[theContact UID]] &&
98                            (!(oldAliasString = [aliasDict objectForKey:buddyValue]) ||
99                            (![oldAliasString isEqualToString:aliasString]))) {
101                                 //Store the new string in our aliasDict
102                                 if (aliasString) {
103                                         [aliasDict setObject:aliasString forKey:buddyValue];
104                                 } else {
105                                         [aliasDict removeObjectForKey:buddyValue];
106                                 }
107                                 
108                                 //Send it to the main thread
109                                 [accountLookup(purple_buddy_get_account(buddy)) updateContact:theContact
110                                                                                                          toAlias:aliasString];
111                         }
112                 }
113         }
116 //A buddy was removed from the list
117 static void adiumPurpleBlistRemove(PurpleBuddyList *list, PurpleBlistNode *node)
119     NSCAssert(node != nil, @"BlistRemove on null node");
120     if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
121                 PurpleBuddy     *buddy = (PurpleBuddy*) node;
122                 NSValue         *buddyValue = [NSValue valueWithPointer:buddy];
124 //              AILog(@"adiumPurpleBlistRemove %s",purple_buddy_get_name(buddy));
125                 [accountLookup(purple_buddy_get_account(buddy)) removeContact:contactLookupFromBuddy(buddy)];
127                 //Clear our dictionaries
128                 [groupDict removeObjectForKey:buddyValue];
129                 [aliasDict removeObjectForKey:buddyValue];
131                 //Clear the ui_data
132                 [(id)buddy->node.ui_data release]; buddy->node.ui_data = NULL;
133     }
136 static void adiumPurpleBlistDestroy(PurpleBuddyList *list)
138     //Here we're responsible for destroying what we placed in list's ui_data earlier
139     AILog(@"adiumPurpleBlistDestroy");
142 static void adiumPurpleBlistSetVisible(PurpleBuddyList *list, gboolean show)
144     AILog(@"adiumPurpleBlistSetVisible: %i",show);
147 static void adiumPurpleBlistRequestAddBuddy(PurpleAccount *account, const char *username, const char *group, const char *alias)
149         [accountLookup(account) requestAddContactWithUID:[NSString stringWithUTF8String:username]];
152 static void adiumPurpleBlistRequestAddChat(PurpleAccount *account, PurpleGroup *group, const char *alias, const char *name)
154     AILog(@"adiumPurpleBlistRequestAddChat");
157 static void adiumPurpleBlistRequestAddGroup(void)
159     AILog(@"adiumPurpleBlistRequestAddGroup");
162 static PurpleBlistUiOps adiumPurpleBlistOps = {
163     adiumPurpleBlistNewList,
164     adiumPurpleBlistNewNode,
165     adiumPurpleBlistShow,
166     adiumPurpleBlistUpdate,
167     adiumPurpleBlistRemove,
168     adiumPurpleBlistDestroy,
169     adiumPurpleBlistSetVisible,
170     adiumPurpleBlistRequestAddBuddy,
171     adiumPurpleBlistRequestAddChat,
172     adiumPurpleBlistRequestAddGroup
175 PurpleBlistUiOps *adium_purple_blist_get_ui_ops(void)
177         return &adiumPurpleBlistOps;